package com.yvan.cs.process;

import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yvan.cs.Consts;
import com.yvan.cs.platform.JsonWapper;
import com.yvan.cs.utils.util;
import lombok.val;
import lombok.var;

import java.util.Map;

/**
 * 源格式
 * <pre>
 * JavaGenerator:
 *   namespace: "com.jztd.sys.SysDict"
 *   basePath: "./effect/java/ent/src/main/java"
 *   Controller:
 *     namespace: "com.jztd.sys.SysDict.controller.SysDictController"
 *     forTable: "Table"
 *     Rest: "/SysDict"
 *     template: "Controller.java.vm"
 *   Service:
 *     namespace: "com.jztd.sys.SysDict.service.SysDictService"
 *     forTable: "Table"
 *     template: "Service.java.vm"
 *   Entity:
 *     namespace: "com.jztd.sys.SysDict.entity."
 *     forTable: "Table"
 *     template: "Entity.java.vm"
 *   Mapper:
 *     namespace: "com.jztd.sys.SysDict.dao.Mapper"
 *     forTable: "Table"
 *     template: "Mapper.java.vm"
 *   Vo:
 *     namespace: "com.jztd.sys.SysDict.vo.Query"
 *     forAction: "query"
 *     forTable: "Table"
 *     template: "Vo.java.vm"
 *
 * 目标格式
 * Table:
 *   _entity:   #实体类
 *     imports:
 *     - "import java.lang.String;"
 *     - "import org.joda.time.DateTime;"
 *     namespace: com.jztd.ent.sysdict.entity
 *     className: DictList
 *     fullClassName: com.jztd.ent.sys_dict.entity.DictList
 *     basePath: ./aaa
 *
 *   _action:
 *      update:
 *      delete:
 *      query:
 *      relation:
 *      insert:
 *          _controller:
 *              imports:
 *              - "import java.lang.String;"
 *              - "import org.joda.time.DateTime;"
 *              namespace: com.jztd.ent.sysdict.entity
 *              className: DictList
 *              fullClassName: com.jztd.ent.sys_dict.entity.DictList
 *              basePath: ./aaa
 *              url: .../
 *          _service:
 *              imports:
 *              - "import java.lang.String;"
 *              - "import org.joda.time.DateTime;"
 *              namespace: com.jztd.ent.sysdict.entity
 *              className: DictList
 *              fullClassName: com.jztd.ent.sys_dict.entity.DictList
 *              basePath: ./aaa
 *          _mapper:
 *              imports:
 *              - "import java.lang.String;"
 *              - "import org.joda.time.DateTime;"
 *              namespace: com.jztd.ent.sysdict.entity
 *              className: DictList
 *              fullClassName: com.jztd.ent.sys_dict.entity.DictList
 *              basePath: ./aaa
 *          _vo:
 *              imports:
 *              - "import java.lang.String;"
 *              - "import org.joda.time.DateTime;"
 *              namespace: com.jztd.ent.sysdict.entity
 *              className: DictList
 *              fullClassName: com.jztd.ent.sys_dict.entity.DictList
 *              basePath: ./aaa
 *
 *
 * </pre>
 * <ul>
 * <li>如果下级没有定义具体的 forTable ，就要报错</li>
 * <li>如果下级 namespace 为空，或者下级 namespace 不是以 com. 开头。那么下级就会继承上级的 namespace</li>
 * <li>如果继承，真实 namespace = 上级 namespace + [.下级namespace] + .Table.TableId</li>
 * <li>如果不继承，真实 namespace = 下级namespace </li>
 * </ul>
 */
public class JavaProcess {

    public static void process(JsonWapper jw) {

        Map<String, JsonWapper> define = Maps.newLinkedHashMap();
        // key:
        //   controller   所有 controller
        //   controller.table 某个实体类的 controller
        //   controller.table.query 某个实体类的某个action的controller
        // value:
        //   他的Map

        for (val category : Consts.JAVA_CATEGORYS) {

            final Iterable<JsonWapper> wappers = jw.isArray(Consts.JAVA_GENERATOR, category) ?
                    jw.asJsonWapperList(Consts.JAVA_GENERATOR, category) :
                    Lists.newArrayList(new JsonWapper(jw.asMap(Consts.JAVA_GENERATOR, category)));

            for (val action : wappers) {
                var namespace = action.asStr(Consts.JAVA_NAMESPACE);
                var basePath = action.asStr(Consts.JAVA_BASE_PATH);
                var disable = action.asBoolean(Consts.JAVA_DISABLE);
                var forTable = action.asStr(Consts.JAVA_FOR_TABLE);
                var forAction = action.asStr(Consts.JAVA_FOR_ACTION);
                val template = action.asStr(Consts.JAVA_TEMPLATE);
                val url = action.asStr(Consts.JAVA_URL);
                val fileKey = util.basePathNamespacePath(basePath, namespace);

                if (Consts.JAVA_ENTITY.equals(category)) {
                    //ENTITY 的定义
                    if (Strings.isNullOrEmpty(forTable)) {
                        throw new RuntimeException("entity not define:" + forTable);
                    }

                    //写入 Table.Entity
                    jw.asDic(forTable, Consts.TABLE_ENTITY)
                            .set(Consts.JAVA_NAMESPACE, util.namespacePath(namespace))
                            .set(Consts.JAVA_CLASS_NAME, util.className(namespace))
                            .set(Consts.JAVA_FULL_CLASS_NAME, namespace)
                            .set(Consts.JAVA_FILE, fileKey);

                    //写入 /File
                    jw.asDic(Consts.File, fileKey)
                            .set(Consts.JAVA_CATEGORY, Consts.JAVA_ENTITY)
                            .set(Consts.JAVA_DISABLE, disable)
                            .set(Consts.JAVA_IMPORTS, jw.asList(forTable, Consts.TABLE_ENTITY, Consts.TABLE_ENTITY_IMPORTS))
                            .set(Consts.JAVA_NAMESPACE, util.namespacePath(namespace))
                            .set(Consts.JAVA_CLASS_NAME, util.className(namespace))
                            .set(Consts.JAVA_FULL_CLASS_NAME, namespace)
                            .set(Consts.JAVA_FOR_TABLE, forTable)
                            .set(Consts.JAVA_TEMPLATE, template);

                    //删除掉 Table.entity.imports
                    jw.remove(forTable, Consts.TABLE_ENTITY, Consts.TABLE_ENTITY_IMPORTS);

                } else {
                    //循环所有 category, 除 ENTITY 之外
                    define.put(
                            Joiner.on("." ).join(category, forTable, forAction),
                            action
                    );
                }
            }
        }

        for (val meTable : util.tableNames(jw)) {
            //循环所有表格
            JsonWapper jwTable = jw.asDic(meTable);
            for (val meAction : jwTable.keys(Consts.TABLE_ACTION)) {
                //和他的action

                for (val meCategory : Consts.JAVA_CATEGORYS) {
                    //和所有的 category

                    if (Consts.JAVA_ENTITY.equals(meCategory))
                        //entity 不参与扫描
                        continue;

                    JsonWapper action;
                    //取专门的 category+table+action 定义
                    action = define.get(meCategory + "." + meTable + "." + meAction);
                    if (action == null) {
                        //取专门的 category+table 定义
                        action = define.get(meCategory + "." + meTable + "." );
                        if (action == null) {
                            //取专门的 category 定义
                            action = define.get(meCategory + ".." );
                            if (action == null) {
                                if (Consts.JAVA_VO.equals(meCategory)) {
                                    //VO 可以不定义
                                    continue;
                                }
                                throw new RuntimeException("没有定义 action的生成内容:" + meCategory + "." + meTable + "." + meAction);
                            }
                        }
                    }

                    //取对应的属性
                    var namespace = action.asStr(Consts.JAVA_NAMESPACE);
                    var basePath = action.asStr(Consts.JAVA_BASE_PATH);
                    var disable = action.asBoolean(Consts.JAVA_DISABLE);
                    val forTable = action.asStr(Consts.JAVA_FOR_TABLE);
                    val forAction = action.asStr(Consts.JAVA_FOR_ACTION);
                    val template = action.asStr(Consts.JAVA_TEMPLATE);
                    val url = action.asStr(Consts.JAVA_URL);
                    val fileKey = util.basePathNamespacePath(basePath, namespace);

                    //写入 Table.Entity
                    jw.asDic(meTable, Consts.TABLE_ACTION, meAction, meCategory)
                            .set(Consts.JAVA_NAMESPACE, util.namespacePath(namespace))
                            .set(Consts.JAVA_CLASS_NAME, util.className(namespace))
                            .set(Consts.JAVA_FULL_CLASS_NAME, namespace)
                            .set(Consts.JAVA_FILE, fileKey);

                    //写入 /File
                    if (!jw.contains(Consts.File, fileKey)) {
                        jw.asDic(Consts.File, fileKey)
                                .set(Consts.JAVA_CATEGORY, meCategory)
                                .set(Consts.JAVA_DISABLE, disable)
                                .set(Consts.JAVA_IMPORTS, Lists.newArrayList())
                                .set(Consts.JAVA_NAMESPACE, util.namespacePath(namespace))
                                .set(Consts.JAVA_CLASS_NAME, util.className(namespace))
                                .set(Consts.JAVA_FULL_CLASS_NAME, namespace)
                                .set(Consts.JAVA_ACTION, Sets.newLinkedHashSet())
                                .set(Consts.JAVA_TEMPLATE, template);
                    }

                    //标记自己的实现
                    jw.asList(Consts.File, fileKey, Consts.JAVA_ACTION).add(
                            meTable + "." + Consts.TABLE_ACTION + "." + meAction
                    );

                }
            }
        }
        jw.remove(Consts.JAVA_GENERATOR);
    }

}
